#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>

/**
 * @brief 错误处理函数
 * @param msg 错误消息
 */
static void die(const char *msg) {
    int err = errno;
    fprintf(stderr, "[%d] %s\n", err, msg);
    abort();
}

/**
 * @brief 消息处理函数
 * @param msg 消息
 */
static void msg(const char *msg) {
    fprintf(stderr, "%s\n", msg);
}

/**
 * @brief 从缓冲区读取32位整数
 * @param buf 缓冲区
 * @return 32位整数
 */
static uint32_t read_le32(const uint8_t *buf) {
    uint32_t val = 0;
    memcpy(&val, buf, 4);
    return val;
}

/**
 * @brief 向缓冲区写入32位整数
 * @param buf 缓冲区
 * @param val 32位整数
 */
static void write_le32(uint8_t *buf, uint32_t val) {
    memcpy(buf, &val, 4);
}

/**
 * @brief 从缓冲区读取64位整数
 * @param buf 缓冲区
 * @return 64位整数
 */
static uint64_t read_le64(const uint8_t *buf) {
    uint64_t val = 0;
    memcpy(&val, buf, 8);
    return val;
}

/**
 * @brief 从缓冲区读取双精度浮点数
 * @param buf 缓冲区
 * @return 双精度浮点数
 */
static double read_dbl(const uint8_t *buf) {
    double val = 0;
    memcpy(&val, buf, 8);
    return val;
}

/**
 * @brief 序列化类型
 */
enum {
    SER_NIL = 0,    // 空值
    SER_ERR = 1,    // 错误码 + 消息
    SER_STR = 2,    // 字符串
    SER_INT = 3,    // int64
    SER_DBL = 4,    // double
    SER_ARR = 5,    // 数组
};

/**
 * @brief 读取完整数据
 * @param fd 文件描述符
 * @param buf 缓冲区
 * @param n 要读取的字节数
 * @return 成功返回0，失败返回-1
 */
static int32_t read_full(int fd, char *buf, size_t n) {
    while (n > 0) {
        ssize_t rv = read(fd, buf, n);
        if (rv <= 0) {
            return -1;  // 错误或EOF
        }
        assert((size_t)rv <= n);
        n -= (size_t)rv;
        buf += rv;
    }
    return 0;
}

/**
 * @brief 写入完整数据
 * @param fd 文件描述符
 * @param buf 缓冲区
 * @param n 要写入的字节数
 * @return 成功返回0，失败返回-1
 */
static int32_t write_all(int fd, const char *buf, size_t n) {
    while (n > 0) {
        ssize_t rv = write(fd, buf, n);
        if (rv <= 0) {
            return -1;  // 错误
        }
        assert((size_t)rv <= n);
        n -= (size_t)rv;
        buf += rv;
    }
    return 0;
}

/**
 * @brief 发送请求到服务器
 * @param fd 文件描述符
 * @param cmd 命令向量
 * @return 成功返回0，失败返回-1
 */
static int32_t send_req(int fd, const std::vector<std::string> &cmd) {
    uint32_t len = 4;
    for (const std::string &s : cmd) {
        len += 4 + s.size();
    }
    if (len > 4096) {
        return -1;
    }

    char wbuf[4 + 4096];
    write_le32((uint8_t *)&wbuf[0], len);
    uint32_t n = cmd.size();
    write_le32((uint8_t *)&wbuf[4], n);
    size_t cur = 8;
    for (const std::string &s : cmd) {
        uint32_t p = (uint32_t)s.size();
        write_le32((uint8_t *)&wbuf[cur], p);
        memcpy(&wbuf[cur + 4], s.data(), s.size());
        cur += 4 + s.size();
    }

    uint32_t total_len = len + 4;
    return write_all(fd, wbuf, total_len) == 0 ? 0 : -1;
}

/**
 * @brief 解析响应数据
 * @param data 响应数据
 * @param len 数据长度
 * @param pos 当前位置
 * @param indent 缩进级别
 * @return 解析成功返回0，失败返回-1
 */
static int32_t parse_response(const uint8_t *data, uint32_t len, uint32_t &pos, int indent = 0) {
    if (pos >= len) {
        return -1;
    }

    std::string prefix(indent * 2, ' ');
    
    switch (data[pos++]) {
    case SER_NIL:
        printf("%s(nil)\n", prefix.c_str());
        return 0;
    case SER_ERR:
        if (pos + 8 > len) {
            return -1;
        }
        {
            int32_t code = 0;
            uint32_t msg_len = 0;
            memcpy(&code, &data[pos], 4);
            memcpy(&msg_len, &data[pos + 4], 4);
            pos += 8;
            if (pos + msg_len > len) {
                return -1;
            }
            printf("%s(err) %d %.*s\n", prefix.c_str(), code, msg_len, &data[pos]);
            pos += msg_len;
        }
        return 0;
    case SER_STR:
        if (pos + 4 > len) {
            return -1;
        }
        {
            uint32_t str_len = read_le32(&data[pos]);
            pos += 4;
            if (pos + str_len > len) {
                return -1;
            }
            printf("%s(str) \"%.*s\"\n", prefix.c_str(), str_len, &data[pos]);
            pos += str_len;
        }
        return 0;
    case SER_INT:
        if (pos + 8 > len) {
            return -1;
        }
        {
            int64_t val = (int64_t)read_le64(&data[pos]);
            pos += 8;
            printf("%s(int) %ld\n", prefix.c_str(), val);
        }
        return 0;
    case SER_DBL:
        if (pos + 8 > len) {
            return -1;
        }
        {
            double val = read_dbl(&data[pos]);
            pos += 8;
            printf("%s(dbl) %g\n", prefix.c_str(), val);
        }
        return 0;
    case SER_ARR:
        if (pos + 4 > len) {
            return -1;
        }
        {
            uint32_t arr_len = read_le32(&data[pos]);
            pos += 4;
            printf("%s(arr) len=%u\n", prefix.c_str(), arr_len);
            for (uint32_t i = 0; i < arr_len; ++i) {
                printf("%s[%u] ", prefix.c_str(), i);
                if (parse_response(data, len, pos, indent + 1) != 0) {
                    return -1;
                }
            }
        }
        return 0;
    default:
        return -1;
    }
}

/**
 * @brief 读取服务器响应
 * @param fd 文件描述符
 * @return 成功返回0，失败返回-1
 */
static int32_t read_res(int fd) {
    // 读取4字节长度头
    char rbuf[4 + 4096 + 1];
    errno = 0;
    int32_t err = read_full(fd, rbuf, 4);
    if (err != 0) {
        if (errno == 0) {
            msg("连接已关闭");
        } else {
            msg("读取错误");
        }
        return err;
    }

    uint32_t len = read_le32((uint8_t *)rbuf);
    if (len > 4096) {
        msg("响应过长");
        return -1;
    }

    // 读取响应主体
    err = read_full(fd, &rbuf[4], len);
    if (err != 0) {
        msg("读取错误");
        return -1;
    }

    // 解析并显示响应
    uint32_t pos = 4;
    int32_t rv = parse_response((uint8_t *)rbuf, 4 + len, pos);
    if (rv != 0) {
        msg("解析错误");
        return -1;
    }
    if (pos != 4 + len) {
        msg("尾部垃圾");
        return -1;
    }
    return 0;
}

/**
 * @brief 分割字符串为命令参数
 * @param input 输入字符串
 * @return 分割后的参数向量
 */
static std::vector<std::string> split_command(const std::string &input) {
    std::vector<std::string> args;
    std::istringstream iss(input);
    std::string arg;
    
    while (iss >> arg) {
        args.push_back(arg);
    }
    
    return args;
}

/**
 * @brief 显示帮助信息
 */
static void show_help() {
    printf("\n=== Redis 交互式客户端帮助 ===\n");
    printf("支持的命令:\n");
    printf("  GET key                    - 获取键的值\n");
    printf("  SET key value              - 设置键值对\n");
    printf("  DEL key                    - 删除键\n");
    printf("  KEYS                       - 列出所有键\n");
    printf("  ZADD zset score member     - 向有序集合添加成员\n");
    printf("  ZREM zset member           - 从有序集合删除成员\n");
    printf("  ZSCORE zset member         - 获取有序集合成员分数\n");
    printf("  ZQUERY zset score name offset limit - 查询有序集合\n");
    printf("  PEXPIRE key milliseconds   - 设置键过期时间（毫秒）\n");
    printf("  PTTL key                   - 获取键剩余过期时间\n");
    printf("  HELP                       - 显示此帮助信息\n");
    printf("  QUIT/EXIT                  - 退出客户端\n");
    printf("\n示例:\n");
    printf("  > SET mykey hello\n");
    printf("  > GET mykey\n");
    printf("  > ZADD myzset 1.5 member1\n");
    printf("  > ZSCORE myzset member1\n");
    printf("=============================\n\n");
}

/**
 * @brief 检查连接是否仍然有效
 * @param fd 文件描述符
 * @return 连接有效返回true
 */
static bool is_connection_alive(int fd) {
    char test_byte;
    ssize_t result = recv(fd, &test_byte, 1, MSG_PEEK | MSG_DONTWAIT);
    if (result == 0) {
        return false; // 连接已关闭
    }
    if (result < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
        return false; // 连接错误
    }
    return true; // 连接正常或没有数据可读
}

/**
 * @brief 尝试重新连接到服务器
 * @return 成功返回新的文件描述符，失败返回-1
 */
static int reconnect_to_server() {
    printf("🔄 尝试重新连接到服务器...\n");
    
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        printf("❌ 创建socket失败\n");
        return -1;
    }

    struct sockaddr_in addr = {};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(1234);
    addr.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);  // 127.0.0.1
    
    int rv = connect(fd, (const struct sockaddr *)&addr, sizeof(addr));
    if (rv) {
        printf("❌ 重连失败，请确保Redis服务器正在运行\n");
        close(fd);
        return -1;
    }
    
    printf("✅ 重新连接成功\n");
    return fd;
}

/**
 * @brief 主函数
 */
int main() {
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        die("socket()");
    }

    struct sockaddr_in addr = {};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(1234);
    addr.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);  // 127.0.0.1
    
    int rv = connect(fd, (const struct sockaddr *)&addr, sizeof(addr));
    if (rv) {
        die("连接失败，请确保Redis服务器正在运行");
    }

    printf("🎉 已连接到Redis服务器 (127.0.0.1:1234)\n");
    printf("输入 'HELP' 查看帮助信息，输入 'QUIT' 退出\n");
    printf("========================================\n");

    std::string input;
    while (true) {
        printf("redis> ");
        fflush(stdout);
        
        if (!std::getline(std::cin, input)) {
            // EOF (Ctrl+D)
            printf("\n再见！\n");
            break;
        }
        
        // 去除前后空白
        size_t start = input.find_first_not_of(" \t");
        if (start == std::string::npos) {
            continue; // 空行
        }
        size_t end = input.find_last_not_of(" \t");
        input = input.substr(start, end - start + 1);
        
        if (input.empty()) {
            continue;
        }
        
        // 检查退出命令
        if (input == "QUIT" || input == "quit" || input == "EXIT" || input == "exit") {
            printf("再见！\n");
            break;
        }
        
        // 检查帮助命令
        if (input == "HELP" || input == "help") {
            show_help();
            continue;
        }
        
        // 检查连接状态
        if (!is_connection_alive(fd)) {
            printf("⚠️  检测到连接断开\n");
            close(fd);
            fd = reconnect_to_server();
            if (fd < 0) {
                printf("❌ 无法重新连接，退出程序\n");
                break;
            }
        }
        
        // 分割命令
        std::vector<std::string> cmd = split_command(input);
        if (cmd.empty()) {
            continue;
        }
        
        // 发送命令到服务器
        if (send_req(fd, cmd) != 0) {
            printf("❌ 发送命令失败，尝试重新连接...\n");
            close(fd);
            fd = reconnect_to_server();
            if (fd < 0) {
                printf("❌ 无法重新连接，退出程序\n");
                break;
            }
            // 重试发送命令
            if (send_req(fd, cmd) != 0) {
                printf("❌ 重试发送命令仍然失败\n");
                continue;
            }
        }
        
        // 读取并显示响应
        if (read_res(fd) != 0) {
            printf("❌ 读取响应失败，尝试重新连接...\n");
            close(fd);
            fd = reconnect_to_server();
            if (fd < 0) {
                printf("❌ 无法重新连接，退出程序\n");
                break;
            }
            continue;
        }
        
        printf("\n");
    }

    close(fd);
    return 0;
} 